#pragma once
// -------------------------------------------------
// BlinKit - BlinKit Library
// -------------------------------------------------
//   File Name: theme_helpers.h
// Description: Theme Helper Classes
//      Author: Ziming Li
//     Created: 2022-04-26
// -------------------------------------------------
// Copyright (C) 2022 MingYang Software Technology.
// -------------------------------------------------

#ifndef BLINKIT_THEME_HELPERS_H
#define BLINKIT_THEME_HELPERS_H

#include <Uxtheme.h>
#include "blinkit/blink/public/platform/web_theme_engine.h"
#include "blinkit/blink/renderer/wtf/Allocator.h"

namespace BlinKit {

/**
 * ThemeDataCache Stuff
 */

class ThemeDataCache
{
public:
    static std::unique_ptr<ThemeDataCache> Create(HMODULE hUxTheme);
    virtual ~ThemeDataCache(void) = default;

    using Creator = decltype(OpenThemeDataForDpi) *;
    Creator GetCreator(void) const { return m_creator; }

    class Storage {
    public:
        Storage(void) = default;
        ~Storage(void);

        HTHEME Get(PCWSTR classList) const;
        void Save(PCWSTR classList, HTHEME hTheme);
    private:
        std::unordered_map<PCWSTR, HTHEME> m_themes;
    };
    virtual Storage& GetStorage(UINT dpi);
protected:
    ThemeDataCache(Creator creator) : m_creator(creator) {}
private:
    static HTHEME WINAPI OpenThemeWrapper(HWND h, PCWSTR classList, UINT);

    Creator m_creator;
    Storage m_storage;
};

class ThemeDataCacheEx final : public ThemeDataCache
{
public:
    ThemeDataCacheEx(Creator creator) : ThemeDataCache(creator) {}
private:
    Storage& GetStorage(UINT dpi) override;

    Storage m_otherStorages[DPI_LEVELS - 1]; // 96 is excluded
};

/**
 * ThemePainter Stuff
 */

class ThemePainter
{
public:
    static std::unique_ptr<ThemePainter> Create(void);
    virtual ~ThemePainter(void) = default;

    using Part = WebThemeEngine::Part;
    using State = WebThemeEngine::State;
    using ExtraParams = WebThemeEngine::ExtraParams;
    using ButtonExtraParams = WebThemeEngine::ButtonExtraParams;
    using MenuListExtraParams = WebThemeEngine::MenuListExtraParams;
    using ProgressBarExtraParams = WebThemeEngine::ProgressBarExtraParams;
    using ScrollbarTrackExtraParams = WebThemeEngine::ScrollbarTrackExtraParams;
    using TextFieldExtraParams = WebThemeEngine::TextFieldExtraParams;

    virtual void Paint(HDC hdc, Part part, State state, const IntRect &rect, const ExtraParams *extra);
protected:
    static void FillSolidRect(HDC hdc, const RECT &rc, COLORREF color);
};

class User32ThemePainter final : public ThemePainter
{
public:
    User32ThemePainter(void) = default;
private:
    void Paint(HDC hdc, Part part, State state, const IntRect &rect, const ExtraParams *extra) override;
};

class UxThemePainter final : public ThemePainter
{
public:
    UxThemePainter(HMODULE hUxTheme);
    ~UxThemePainter(void) override;
private:
    class Session {
        STACK_ALLOCATED()
    public:
        Session(HDC hdc, ThemeDataCache &cache);

        void Draw(HDC hdc, PCWSTR classList, int partId, int stateId, const IntSize &size);
        void Draw(HDC hdc, PCWSTR classList, int partId, int stateId, const RECT &rect, const DTBGOPTS *options = nullptr);
    private:
        Session(UINT dpi, ThemeDataCache &cache);

        const UINT m_dpi;
        ThemeDataCache::Creator m_creator;
        ThemeDataCache::Storage &m_storage;
    };

    static int AdjustButtonStateId(State state, const ButtonExtraParams &extra);
    static int AdjustCheckboxStateId(State state, const ButtonExtraParams &extra);
    static int AdjustRadioStateId(State state, const ButtonExtraParams &extra);
    void PaintButton(Session &session, HDC hdc, Part part, State state, const IntSize &size, const ButtonExtraParams &extra);

    struct ComboBoxState;
    static ComboBoxState AdjustComboBoxState(State state);
    void PaintMenuList(Session &session, HDC hdc, State state, const IntRect &rect, const MenuListExtraParams &extra);

    void PaintProgressBar(Session &session, HDC hdc, State state, const IntRect &rect, const ProgressBarExtraParams &extra);

    void PaintScrollArrow(Session &session, HDC hdc, Part part, State state, const IntSize &size, const ScrollbarTrackExtraParams &extra);
    void PaintScrollPart(Session &session, HDC hdc, Part part, State state, const IntSize &size, const ScrollbarTrackExtraParams &extra);

    void PaintTextField(Session &session, HDC hdc, State state, const IntSize &size, const TextFieldExtraParams &extra);

    void Paint(HDC hdc, Part part, State state, const IntRect &rect, const ExtraParams *extra) override;

    HMODULE m_hUxTheme;
    std::unique_ptr<ThemeDataCache> m_cache;
};

} // namespace BlinKit

#endif // BLINKIT_THEME_HELPERS_H
